package com.abhinav;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DeadlockTest {
	public static void main(String[] args) {
		Resource res = new Resource();

		// ExecutorService exec1 = Executors.newCachedThreadPool();
		// exec1.execute(new Thread1(res));
		// ExecutorService exec2 = Executors.newCachedThreadPool();
		// exec2.execute(new Thread2(res));
		//
		// exec1.shutdown();
		// exec2.shutdown();

//		Thread th1 = new Thread(new Thread1(res));
//		th1.start();
//
//		Thread th2 = new Thread(new Thread2(res));
//		th2.start();
		
		new Thread(new ThreadOne(), "ThreadOne").start();
		new Thread(new ThreadTwo(), "ThreadTwo").start();

	}

	static class ThreadOne implements Runnable {
		public void run() {
			synchronized (Integer.class) {
				System.out.println(Thread.currentThread().getName() + " - Got lock on Integer.class");
				synchronized (String.class) {
					System.out.println(Thread.currentThread().getName() + " - Got lock on String.class");
				}
			}
		}
	}

	static class ThreadTwo implements Runnable {
		public void run() {
			synchronized (String.class) {
				System.out.println(Thread.currentThread().getName() + " - Got lock on String.class");
				synchronized (Integer.class) {
					System.out.println(Thread.currentThread().getName() + " - Got lock on Integer.class");
				}
			}
		}

	}

}

class Resource {
	public void method1() {
		synchronized (String.class) {
			System.out.println("Aquired lock on String.class object");
			synchronized (Integer.class) {
				System.out.println("Aquired lock on Integer.class object");
			}
		}
	}

	public void method2() {
		synchronized (Integer.class) {
			System.out.println("Aquired lock on Integer.class object");
			synchronized (String.class) {
				System.out.println("Aquired lock on String.class object");
			}
		}
	}
}

class Thread1 implements Runnable {
	Resource res;

	public Thread1(Resource res) {
		this.res = res;
	}

	@Override
	public void run() {
		res.method1();
	}

}

class Thread2 implements Runnable {
	Resource res;

	public Thread2(Resource res) {
		this.res = res;
	}

	@Override
	public void run() {
		res.method2();
	}

}